#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR) #pragma warning disable using System; using System.Collections; using System.IO; using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1; using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1.Cms; using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1.Nist; using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1.X509; using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto; using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Engines; using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Generators; using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.IO; using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters; using BestHTTP.SecureProtocol.Org.BouncyCastle.Security; using BestHTTP.SecureProtocol.Org.BouncyCastle.Security.Certificates; using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities; using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.IO; using BestHTTP.SecureProtocol.Org.BouncyCastle.X509; namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Cms { /** * General class for generating a CMS enveloped-data message stream. * <p> * A simple example of usage. * <pre> * CmsEnvelopedDataStreamGenerator edGen = new CmsEnvelopedDataStreamGenerator(); * * edGen.AddKeyTransRecipient(cert); * * MemoryStream bOut = new MemoryStream(); * * Stream out = edGen.Open( * bOut, CMSEnvelopedDataGenerator.AES128_CBC);* * out.Write(data); * * out.Close(); * </pre> * </p> */ public class CmsEnvelopedDataStreamGenerator : CmsEnvelopedGenerator { private object _originatorInfo = null; private object _unprotectedAttributes = null; private int _bufferSize; private bool _berEncodeRecipientSet; public CmsEnvelopedDataStreamGenerator() { } /// <summary>Constructor allowing specific source of randomness</summary> /// <param name="rand">Instance of <c>SecureRandom</c> to use.</param> public CmsEnvelopedDataStreamGenerator( SecureRandom rand) : base(rand) { } /// <summary>Set the underlying string size for encapsulated data.</summary> /// <param name="bufferSize">Length of octet strings to buffer the data.</param> public void SetBufferSize( int bufferSize) { _bufferSize = bufferSize; } /// <summary>Use a BER Set to store the recipient information.</summary> public void SetBerEncodeRecipients( bool berEncodeRecipientSet) { _berEncodeRecipientSet = berEncodeRecipientSet; } private DerInteger Version { get { int version = (_originatorInfo != null || _unprotectedAttributes != null) ? 2 : 0; return new DerInteger(version); } } /// <summary> /// Generate an enveloped object that contains an CMS Enveloped Data /// object using the passed in key generator. /// </summary> private Stream Open( Stream outStream, string encryptionOid, CipherKeyGenerator keyGen) { byte[] encKeyBytes = keyGen.GenerateKey(); KeyParameter encKey = ParameterUtilities.CreateKeyParameter(encryptionOid, encKeyBytes); Asn1Encodable asn1Params = GenerateAsn1Parameters(encryptionOid, encKeyBytes); ICipherParameters cipherParameters; AlgorithmIdentifier encAlgID = GetAlgorithmIdentifier( encryptionOid, encKey, asn1Params, out cipherParameters); Asn1EncodableVector recipientInfos = new Asn1EncodableVector(); foreach (RecipientInfoGenerator rig in recipientInfoGenerators) { try { recipientInfos.Add(rig.Generate(encKey, rand)); } catch (InvalidKeyException e) { throw new CmsException("key inappropriate for algorithm.", e); } catch (GeneralSecurityException e) { throw new CmsException("error making encrypted content.", e); } } return Open(outStream, encAlgID, cipherParameters, recipientInfos); } private Stream Open( Stream outStream, AlgorithmIdentifier encAlgID, ICipherParameters cipherParameters, Asn1EncodableVector recipientInfos) { try { // // ContentInfo // BerSequenceGenerator cGen = new BerSequenceGenerator(outStream); cGen.AddObject(CmsObjectIdentifiers.EnvelopedData); // // Encrypted Data // BerSequenceGenerator envGen = new BerSequenceGenerator( cGen.GetRawOutputStream(), 0, true); envGen.AddObject(this.Version); Stream envRaw = envGen.GetRawOutputStream(); Asn1Generator recipGen = _berEncodeRecipientSet ? (Asn1Generator) new BerSetGenerator(envRaw) : new DerSetGenerator(envRaw); foreach (Asn1Encodable ae in recipientInfos) { recipGen.AddObject(ae); } recipGen.Close(); BerSequenceGenerator eiGen = new BerSequenceGenerator(envRaw); eiGen.AddObject(CmsObjectIdentifiers.Data); eiGen.AddObject(encAlgID); Stream octetOutputStream = CmsUtilities.CreateBerOctetOutputStream( eiGen.GetRawOutputStream(), 0, false, _bufferSize); IBufferedCipher cipher = CipherUtilities.GetCipher(encAlgID.Algorithm); cipher.Init(true, new ParametersWithRandom(cipherParameters, rand)); CipherStream cOut = new CipherStream(octetOutputStream, null, cipher); return new CmsEnvelopedDataOutputStream(this, cOut, cGen, envGen, eiGen); } catch (SecurityUtilityException e) { throw new CmsException("couldn't create cipher.", e); } catch (InvalidKeyException e) { throw new CmsException("key invalid in message.", e); } catch (IOException e) { throw new CmsException("exception decoding algorithm parameters.", e); } } /** * generate an enveloped object that contains an CMS Enveloped Data object * @throws IOException */ public Stream Open( Stream outStream, string encryptionOid) { CipherKeyGenerator keyGen = GeneratorUtilities.GetKeyGenerator(encryptionOid); keyGen.Init(new KeyGenerationParameters(rand, keyGen.DefaultStrength)); return Open(outStream, encryptionOid, keyGen); } /** * generate an enveloped object that contains an CMS Enveloped Data object * @throws IOException */ public Stream Open( Stream outStream, string encryptionOid, int keySize) { CipherKeyGenerator keyGen = GeneratorUtilities.GetKeyGenerator(encryptionOid); keyGen.Init(new KeyGenerationParameters(rand, keySize)); return Open(outStream, encryptionOid, keyGen); } private class CmsEnvelopedDataOutputStream : BaseOutputStream { private readonly CmsEnvelopedGenerator _outer; private readonly CipherStream _out; private readonly BerSequenceGenerator _cGen; private readonly BerSequenceGenerator _envGen; private readonly BerSequenceGenerator _eiGen; public CmsEnvelopedDataOutputStream( CmsEnvelopedGenerator outer, CipherStream outStream, BerSequenceGenerator cGen, BerSequenceGenerator envGen, BerSequenceGenerator eiGen) { _outer = outer; _out = outStream; _cGen = cGen; _envGen = envGen; _eiGen = eiGen; } public override void WriteByte( byte b) { _out.WriteByte(b); } public override void Write( byte[] bytes, int off, int len) { _out.Write(bytes, off, len); } #if PORTABLE || NETFX_CORE protected override void Dispose(bool disposing) { if (disposing) { BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.Dispose(_out); // TODO Parent context(s) should really be closed explicitly _eiGen.Close(); if (_outer.unprotectedAttributeGenerator != null) { Asn1.Cms.AttributeTable attrTable = _outer.unprotectedAttributeGenerator.GetAttributes(BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.CreateHashtable()); Asn1Set unprotectedAttrs = new BerSet(attrTable.ToAsn1EncodableVector()); _envGen.AddObject(new DerTaggedObject(false, 1, unprotectedAttrs)); } _envGen.Close(); _cGen.Close(); } base.Dispose(disposing); } #else public override void Close() { BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.Dispose(_out); // TODO Parent context(s) should really be closed explicitly _eiGen.Close(); if (_outer.unprotectedAttributeGenerator != null) { Asn1.Cms.AttributeTable attrTable = _outer.unprotectedAttributeGenerator.GetAttributes(BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.CreateHashtable()); Asn1Set unprotectedAttrs = new BerSet(attrTable.ToAsn1EncodableVector()); _envGen.AddObject(new DerTaggedObject(false, 1, unprotectedAttrs)); } _envGen.Close(); _cGen.Close(); base.Close(); } #endif } } } #pragma warning restore #endif